home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / network / base / netkit-b.07a / netkit-b / NetKit-B-0.07A / tftp / main.c next >
Encoding:
C/C++ Source or Header  |  1996-07-20  |  14.1 KB  |  697 lines

  1. /*
  2.  * Copyright (c) 1983 Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *    This product includes software developed by the University of
  16.  *    California, Berkeley and its contributors.
  17.  * 4. Neither the name of the University nor the names of its contributors
  18.  *    may be used to endorse or promote products derived from this software
  19.  *    without specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  */
  33.  
  34. char copyright[] =
  35.   "@(#) Copyright (c) 1983 Regents of the University of California.\n"
  36.   "All rights reserved.\n";
  37.  
  38. /*
  39.  * From: @(#)main.c    5.10 (Berkeley) 3/1/91
  40.  */
  41. char main_rcsid[] = 
  42.   "$Id: main.c,v 1.4 1996/07/20 21:04:16 dholland Exp $";
  43.  
  44. /* Many bug fixes are from Jim Guyton <guyton@rand-unix> */
  45.  
  46. /*
  47.  * TFTP User Program -- Command Interface.
  48.  */
  49. #include <sys/types.h>
  50. #include <sys/socket.h>
  51. #include <sys/file.h>
  52.  
  53. #include <arpa/inet.h>
  54. #include <netinet/in.h>
  55.  
  56. #include <signal.h>
  57. #include <stdio.h>
  58. #include <errno.h>
  59. #include <stdlib.h>
  60. #include <setjmp.h>
  61. #include <string.h>
  62. #include <ctype.h>
  63. #include <netdb.h>
  64. #include <unistd.h>
  65.  
  66. #define    TIMEOUT        5        /* secs between rexmt's */
  67.  
  68. struct    sockaddr_in s_in;
  69. int    f;
  70. short   port;
  71. int    trace;
  72. int    verbose;
  73. int    connected;
  74. char    mode[32];
  75. char    line[200];
  76. int    margc;
  77. char    *margv[20];
  78. char    *prompt = "tftp";
  79. sigjmp_buf    toplevel;
  80. void    intr();
  81. struct    servent *sp;
  82.  
  83. void sendfile(int fd, char *name, char *mode);
  84. void recvfile(int fd, char *name, char *mode);
  85.  
  86. void makeargv(void);
  87. void command(int top);
  88. void quit(int argc, char *argv[]);
  89. void help(int argc, char *argv[]);
  90. void setverbose(int argc, char *argv[]);
  91. void settrace(int argc, char *argv[]);
  92. void status(int argc, char *argv[]);
  93. void get(int argc, char *argv[]);
  94. void put(int argc, char *argv[]);
  95. void setpeer(int argc, char *argv[]);
  96. void modecmd(int argc, char *argv[]);
  97. void setrexmt(int argc, char *argv[]);
  98. void settimeout(int argc, char *argv[]);
  99. void setbinary(int argc, char *argv[]);
  100. void setascii(int argc, char *argv[]);
  101. void setmode(const char *newmode);
  102. void putusage(const char *s);
  103. void getusage(const char *s);
  104.  
  105. #define HELPINDENT (sizeof("connect"))
  106.  
  107. struct cmd {
  108.     char    *name;
  109.     char    *help;
  110.     void    (*handler)(int, char *[]);
  111. };
  112.  
  113. char    vhelp[] = "toggle verbose mode";
  114. char    thelp[] = "toggle packet tracing";
  115. char    chelp[] = "connect to remote tftp";
  116. char    qhelp[] = "exit tftp";
  117. char    hhelp[] = "print help information";
  118. char    shelp[] = "send file";
  119. char    rhelp[] = "receive file";
  120. char    mhelp[] = "set file transfer mode";
  121. char    sthelp[] = "show current status";
  122. char    xhelp[] = "set per-packet retransmission timeout";
  123. char    ihelp[] = "set total retransmission timeout";
  124. char    ashelp[] = "set mode to netascii";
  125. char    bnhelp[] = "set mode to octet";
  126.  
  127. struct cmd cmdtab[] = {
  128.     { "connect",    chelp,        setpeer },
  129.     { "mode",       mhelp,          modecmd },
  130.     { "put",    shelp,        put },
  131.     { "get",    rhelp,        get },
  132.     { "quit",    qhelp,        quit },
  133.     { "verbose",    vhelp,        setverbose },
  134.     { "trace",    thelp,        settrace },
  135.     { "status",    sthelp,        status },
  136.     { "binary",     bnhelp,         setbinary },
  137.     { "ascii",      ashelp,         setascii },
  138.     { "rexmt",    xhelp,        setrexmt },
  139.     { "timeout",    ihelp,        settimeout },
  140.     { "?",        hhelp,        help },
  141.     { 0 }
  142. };
  143.  
  144. struct    cmd *getcmd();
  145. char    *tail();
  146. char    *index();
  147. char    *rindex();
  148.  
  149. int
  150. main(int argc, char *argv[])
  151. {
  152.     struct sockaddr_in s_in;
  153.     int top;
  154.  
  155.     sp = getservbyname("tftp", "udp");
  156.     if (sp == 0) {
  157.         fprintf(stderr, "tftp: udp/tftp: unknown service\n");
  158.         exit(1);
  159.     }
  160.     f = socket(AF_INET, SOCK_DGRAM, 0);
  161.     if (f < 0) {
  162.         perror("tftp: socket");
  163.         exit(3);
  164.     }
  165.     memset(&s_in, 0, sizeof(s_in));
  166.     s_in.sin_family = AF_INET;
  167.     if (bind(f, (struct sockaddr *)&s_in, sizeof (s_in)) < 0) {
  168.         perror("tftp: bind");
  169.         exit(1);
  170.     }
  171.     strcpy(mode, "netascii");
  172.     signal(SIGINT, intr);
  173.     if (argc > 1) {
  174.         if (sigsetjmp(toplevel, 1) != 0)
  175.             exit(0);
  176.         setpeer(argc, argv);
  177.     }
  178.     top = sigsetjmp(toplevel, 1) == 0;
  179.     for (;;)
  180.         command(top);
  181. }
  182.  
  183. char    hostname[100];
  184.  
  185. void
  186. setpeer(int argc, char *argv[])
  187. {
  188.     struct hostent *host;
  189.  
  190.     if (argc < 2) {
  191.         strcpy(line, "Connect ");
  192.         printf("(to) ");
  193.         gets(&line[strlen(line)]);
  194.         makeargv();
  195.         argc = margc;
  196.         argv = margv;
  197.     }
  198.     if (argc > 3) {
  199.         printf("usage: %s host-name [port]\n", argv[0]);
  200.         return;
  201.     }
  202.     host = gethostbyname(argv[1]);
  203.     if (host) {
  204.         s_in.sin_family = host->h_addrtype;
  205.         memcpy(&s_in.sin_addr, host->h_addr, host->h_length);
  206.         strcpy(hostname, host->h_name);
  207.     } else {
  208.         s_in.sin_family = AF_INET;
  209.         s_in.sin_addr.s_addr = inet_addr(argv[1]);
  210.         if (s_in.sin_addr.s_addr == -1) {
  211.             connected = 0;
  212.             printf("%s: unknown host\n", argv[1]);
  213.             return;
  214.         }
  215.         strcpy(hostname, argv[1]);
  216.     }
  217.     port = sp->s_port;
  218.     if (argc == 3) {
  219.         port = atoi(argv[2]);
  220.         if (port < 0) {
  221.             printf("%s: bad port number\n", argv[2]);
  222.             connected = 0;
  223.             return;
  224.         }
  225.         port = htons(port);
  226.     }
  227.     connected = 1;
  228. }
  229.  
  230. struct    modes {
  231.     char *m_name;
  232.     char *m_mode;
  233. } modes[] = {
  234.     { "ascii",    "netascii" },
  235.     { "netascii",   "netascii" },
  236.     { "binary",     "octet" },
  237.     { "image",      "octet" },
  238.     { "octet",     "octet" },
  239. /*      { "mail",       "mail" },       */
  240.     { 0,        0 }
  241. };
  242.  
  243. void
  244. modecmd(int argc, char *argv[])
  245. {
  246.     register struct modes *p;
  247.     char *sep;
  248.  
  249.     if (argc < 2) {
  250.         printf("Using %s mode to transfer files.\n", mode);
  251.         return;
  252.     }
  253.     if (argc == 2) {
  254.         for (p = modes; p->m_name; p++)
  255.             if (strcmp(argv[1], p->m_name) == 0)
  256.                 break;
  257.         if (p->m_name) {
  258.             setmode(p->m_mode);
  259.             return;
  260.         }
  261.         printf("%s: unknown mode\n", argv[1]);
  262.         /* drop through and print usage message */
  263.     }
  264.  
  265.     printf("usage: %s [", argv[0]);
  266.     sep = " ";
  267.     for (p = modes; p->m_name; p++) {
  268.         printf("%s%s", sep, p->m_name);
  269.         if (*sep == ' ')
  270.             sep = " | ";
  271.     }
  272.     printf(" ]\n");
  273.     return;
  274. }
  275.  
  276. void
  277. setbinary(int argc, char *argv[])
  278. {
  279.     setmode("octet");
  280. }
  281.  
  282. void
  283. setascii(int argc, char *argv[])
  284. {
  285.     setmode("netascii");
  286. }
  287.  
  288. void
  289. setmode(const char *newmode)
  290. {
  291.     strcpy(mode, newmode);
  292.     if (verbose)
  293.         printf("mode set to %s\n", mode);
  294. }
  295.  
  296.  
  297. /*
  298.  * Send file(s).
  299.  */
  300. void
  301. put(int argc, char *argv[])
  302. {
  303.     int fd;
  304.     register int n;
  305.     register char *cp, *targ;
  306.  
  307.     if (argc < 2) {
  308.         strcpy(line, "send ");
  309.         printf("(file) ");
  310.         gets(&line[strlen(line)]);
  311.         makeargv();
  312.         argc = margc;
  313.         argv = margv;
  314.     }
  315.     if (argc < 2) {
  316.         putusage(argv[0]);
  317.         return;
  318.     }
  319.     targ = argv[argc - 1];
  320.     if (index(argv[argc - 1], ':')) {
  321.         char *cp;
  322.         struct hostent *hp;
  323.  
  324.         for (n = 1; n < argc - 1; n++)
  325.             if (index(argv[n], ':')) {
  326.                 putusage(argv[0]);
  327.                 return;
  328.             }
  329.         cp = argv[argc - 1];
  330.         targ = index(cp, ':');
  331.         *targ++ = 0;
  332.         hp = gethostbyname(cp);
  333.         if (hp == NULL) {
  334.             fprintf(stderr, "tftp: %s: ", cp);
  335.             herror((char *)NULL);
  336.             return;
  337.         }
  338.         bcopy(hp->h_addr, (caddr_t)&s_in.sin_addr, hp->h_length);
  339.         s_in.sin_family = hp->h_addrtype;
  340.         connected = 1;
  341.         strcpy(hostname, hp->h_name);
  342.     }
  343.     if (!connected) {
  344.         printf("No target machine specified.\n");
  345.         return;
  346.     }
  347.     if (argc < 4) {
  348.         cp = argc == 2 ? tail(targ) : argv[1];
  349.         fd = open(cp, O_RDONLY);
  350.         if (fd < 0) {
  351.             fprintf(stderr, "tftp: "); perror(cp);
  352.             return;
  353.         }
  354.         if (verbose)
  355.             printf("putting %s to %s:%s [%s]\n",
  356.                 cp, hostname, targ, mode);
  357.         s_in.sin_port = port;
  358.         sendfile(fd, targ, mode);
  359.         return;
  360.     }
  361.                 /* this assumes the target is a directory */
  362.                 /* on a remote unix system.  hmmmm.  */
  363.     cp = index(targ, '\0'); 
  364.     *cp++ = '/';
  365.     for (n = 1; n < argc - 1; n++) {
  366.         strcpy(cp, tail(argv[n]));
  367.         fd = open(argv[n], O_RDONLY);
  368.         if (fd < 0) {
  369.             fprintf(stderr, "tftp: "); perror(argv[n]);
  370.             continue;
  371.         }
  372.         if (verbose)
  373.             printf("putting %s to %s:%s [%s]\n",
  374.                 argv[n], hostname, targ, mode);
  375.         s_in.sin_port = port;
  376.         sendfile(fd, targ, mode);
  377.     }
  378. }
  379.  
  380. void
  381. putusage(const char *s)
  382. {
  383.     printf("usage: %s file ... host:target, or\n", s);
  384.     printf("       %s file ... target (when already connected)\n", s);
  385. }
  386.  
  387. /*
  388.  * Receive file(s).
  389.  */
  390. void
  391. get(int argc, char *argv[])
  392. {
  393.     int fd;
  394.     register int n;
  395.     register char *cp;
  396.     char *src;
  397.  
  398.     if (argc < 2) {
  399.         strcpy(line, "get ");
  400.         printf("(files) ");
  401.         gets(&line[strlen(line)]);
  402.         makeargv();
  403.         argc = margc;
  404.         argv = margv;
  405.     }
  406.     if (argc < 2) {
  407.         getusage(argv[0]);
  408.         return;
  409.     }
  410.     if (!connected) {
  411.         for (n = 1; n < argc ; n++)
  412.             if (index(argv[n], ':') == 0) {
  413.                 getusage(argv[0]);
  414.                 return;
  415.             }
  416.     }
  417.     for (n = 1; n < argc ; n++) {
  418.         src = index(argv[n], ':');
  419.         if (src == NULL)
  420.             src = argv[n];
  421.         else {
  422.             struct hostent *hp;
  423.  
  424.             *src++ = 0;
  425.             hp = gethostbyname(argv[n]);
  426.             if (hp == NULL) {
  427.                 fprintf(stderr, "tftp: %s: ", argv[n]);
  428.                 herror((char *)NULL);
  429.                 continue;
  430.             }
  431.             bcopy(hp->h_addr, (caddr_t)&s_in.sin_addr, hp->h_length);
  432.             s_in.sin_family = hp->h_addrtype;
  433.             connected = 1;
  434.             strcpy(hostname, hp->h_name);
  435.         }
  436.         if (argc < 4) {
  437.             cp = argc == 3 ? argv[2] : tail(src);
  438.             fd = creat(cp, 0644);
  439.             if (fd < 0) {
  440.                 fprintf(stderr, "tftp: "); perror(cp);
  441.                 return;
  442.             }
  443.             if (verbose)
  444.                 printf("getting from %s:%s to %s [%s]\n",
  445.                     hostname, src, cp, mode);
  446.             s_in.sin_port = port;
  447.             recvfile(fd, src, mode);
  448.             break;
  449.         }
  450.         cp = tail(src);         /* new .. jdg */
  451.         fd = creat(cp, 0644);
  452.         if (fd < 0) {
  453.             fprintf(stderr, "tftp: "); perror(cp);
  454.             continue;
  455.         }
  456.         if (verbose)
  457.             printf("getting from %s:%s to %s [%s]\n",
  458.                 hostname, src, cp, mode);
  459.         s_in.sin_port = port;
  460.         recvfile(fd, src, mode);
  461.     }
  462. }
  463.  
  464. void
  465. getusage(const char *s)
  466. {
  467.     printf("usage: %s host:file host:file ... file, or\n", s);
  468.     printf("       %s file file ... file if connected\n", s);
  469. }
  470.  
  471. int    rexmtval = TIMEOUT;
  472.  
  473. void
  474. setrexmt(int argc, char *argv[])
  475. {
  476.     int t;
  477.  
  478.     if (argc < 2) {
  479.         strcpy(line, "Rexmt-timeout ");
  480.         printf("(value) ");
  481.         gets(&line[strlen(line)]);
  482.         makeargv();
  483.         argc = margc;
  484.         argv = margv;
  485.     }
  486.     if (argc != 2) {
  487.         printf("usage: %s value\n", argv[0]);
  488.         return;
  489.     }
  490.     t = atoi(argv[1]);
  491.     if (t < 0)
  492.         printf("%s: bad value\n", argv[1]);
  493.     else
  494.         rexmtval = t;
  495. }
  496.  
  497. int    maxtimeout = 5 * TIMEOUT;
  498.  
  499. void
  500. settimeout(int argc, char *argv[])
  501. {
  502.     int t;
  503.  
  504.     if (argc < 2) {
  505.         strcpy(line, "Maximum-timeout ");
  506.         printf("(value) ");
  507.         gets(&line[strlen(line)]);
  508.         makeargv();
  509.         argc = margc;
  510.         argv = margv;
  511.     }
  512.     if (argc != 2) {
  513.         printf("usage: %s value\n", argv[0]);
  514.         return;
  515.     }
  516.     t = atoi(argv[1]);
  517.     if (t < 0)
  518.         printf("%s: bad value\n", argv[1]);
  519.     else
  520.         maxtimeout = t;
  521. }
  522.  
  523. void
  524. status(int argc, char *argv[])
  525. {
  526.     if (connected)
  527.         printf("Connected to %s.\n", hostname);
  528.     else
  529.         printf("Not connected.\n");
  530.     printf("Mode: %s Verbose: %s Tracing: %s\n", mode,
  531.         verbose ? "on" : "off", trace ? "on" : "off");
  532.     printf("Rexmt-interval: %d seconds, Max-timeout: %d seconds\n",
  533.         rexmtval, maxtimeout);
  534. }
  535.  
  536. void
  537. intr(int ignore)
  538. {
  539.     signal(SIGALRM, SIG_IGN);
  540.     alarm(0);
  541.     siglongjmp(toplevel, -1);
  542. }
  543.  
  544. char *
  545. tail(filename)
  546.     char *filename;
  547. {
  548.     register char *s;
  549.     
  550.     while (*filename) {
  551.         s = rindex(filename, '/');
  552.         if (s == NULL)
  553.             break;
  554.         if (s[1])
  555.             return (s + 1);
  556.         *s = '\0';
  557.     }
  558.     return (filename);
  559. }
  560.  
  561. /*
  562.  * Command parser.
  563.  */
  564. void
  565. command(int top)
  566. {
  567.     register struct cmd *c;
  568.  
  569.     if (!top)
  570.         putchar('\n');
  571.     for (;;) {
  572.         printf("%s> ", prompt);
  573.         if (gets(line) == 0) {
  574.             if (feof(stdin)) {
  575.                 quit(0, NULL);
  576.             } else {
  577.                 continue;
  578.             }
  579.         }
  580.         if (line[0] == 0)
  581.             continue;
  582.         makeargv();
  583.         c = getcmd(margv[0]);
  584.         if (c == (struct cmd *)-1) {
  585.             printf("?Ambiguous command\n");
  586.             continue;
  587.         }
  588.         if (c == 0) {
  589.             printf("?Invalid command\n");
  590.             continue;
  591.         }
  592.         (*c->handler)(margc, margv);
  593.     }
  594. }
  595.  
  596. struct cmd *
  597. getcmd(name)
  598.     register char *name;
  599. {
  600.     register char *p, *q;
  601.     register struct cmd *c, *found;
  602.     register int nmatches, longest;
  603.  
  604.     longest = 0;
  605.     nmatches = 0;
  606.     found = 0;
  607.     for (c = cmdtab; (p = c->name)!=NULL; c++) {
  608.         for (q = name; *q == *p++; q++)
  609.             if (*q == 0)        /* exact match? */
  610.                 return (c);
  611.         if (!*q) {            /* the name was a prefix */
  612.             if (q - name > longest) {
  613.                 longest = q - name;
  614.                 nmatches = 1;
  615.                 found = c;
  616.             } else if (q - name == longest)
  617.                 nmatches++;
  618.         }
  619.     }
  620.     if (nmatches > 1)
  621.         return ((struct cmd *)-1);
  622.     return (found);
  623. }
  624.  
  625. /*
  626.  * Slice a string up into argc/argv.
  627.  */
  628. void
  629. makeargv(void)
  630. {
  631.     register char *cp;
  632.     register char **argp = margv;
  633.  
  634.     margc = 0;
  635.     for (cp = line; *cp;) {
  636.         while (isspace(*cp))
  637.             cp++;
  638.         if (*cp == '\0')
  639.             break;
  640.         *argp++ = cp;
  641.         margc += 1;
  642.         while (*cp != '\0' && !isspace(*cp))
  643.             cp++;
  644.         if (*cp == '\0')
  645.             break;
  646.         *cp++ = '\0';
  647.     }
  648.     *argp++ = 0;
  649. }
  650.  
  651. void
  652. quit(int ign1, char *ign2[])
  653. {
  654.     exit(0);
  655. }
  656.  
  657. /*
  658.  * Help command.
  659.  */
  660. void
  661. help(int argc, char *argv[])
  662. {
  663.     register struct cmd *c;
  664.  
  665.     if (argc == 1) {
  666.         printf("Commands may be abbreviated.  Commands are:\n\n");
  667.         for (c = cmdtab; c->name; c++)
  668.             printf("%-*s\t%s\n", HELPINDENT, c->name, c->help);
  669.         return;
  670.     }
  671.     while (--argc > 0) {
  672.         register char *arg;
  673.         arg = *++argv;
  674.         c = getcmd(arg);
  675.         if (c == (struct cmd *)-1)
  676.             printf("?Ambiguous help command %s\n", arg);
  677.         else if (c == (struct cmd *)0)
  678.             printf("?Invalid help command %s\n", arg);
  679.         else
  680.             printf("%s\n", c->help);
  681.     }
  682. }
  683.  
  684. void
  685. settrace(int ign1, char *ign2[])
  686. {
  687.     trace = !trace;
  688.     printf("Packet tracing %s.\n", trace ? "on" : "off");
  689. }
  690.  
  691. void
  692. setverbose(int ign1, char *ign2[])
  693. {
  694.     verbose = !verbose;
  695.     printf("Verbose mode %s.\n", verbose ? "on" : "off");
  696. }
  697.